home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-07 | 52.9 KB | 1,539 lines |
- (c) Copyright 1990 Commodore-Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice,
- and is provided "as is" without warranty of any kind, either express
- or implied. The entire risk as to the use of this information is
- assumed by the user.
-
- Collision Detection Between Animation Objects
-
- by Ken Farinsky
-
- Collision detection allows the system to manage Gel-to-Border and
- Gel-to-Gel collision handling for an application. "Gels" are
- VSprite-based objects that may be displayed and moved about the
- Amiga display. These objects include VSprites (Virtual Sprites),
- Bobs (Blitter Objects), and AnimObs (Animation Objects). For a
- detailed discussion of collision detection between simple Gels
- (such as VSprites and Bobs), see the "Graphics: Sprites, Bobs and
- Animation" chapter in the ROM Kernel Manual: Libraries and
- Devices.
-
- The basic premise of Amiga collision detection is to call a user
- supplied collision routine when two objects overlap. This is
- complicated by two further enhancements. First, borders are
- counted as objects and special-case processing of collisions is
- provided between Gels and the border. Second, each Gel has two
- masks that indicate how pairs of objects will react when they
- collide.
-
- Collision detection between objects such as VSprites and Bobs is
- conceptually very simple. Each object is built upon a single
- underlying structure, the VSprite structure. After the Gel has
- been added to the system, the DoCollision() routine scans the
- list of VSprites for overlapping objects and calls the
- appropriate user-supplied collision routine in the event of a
- collision. Since there is a one-to-one correspondence between
- VSprites and objects, it is obvious which VSprite structure
- belongs to which object on the screen.
-
- Animation Objects Are Not Simple Gels
-
- Animation Objects contain multiple VSprite structures which are
- linked to form a larger object. When the object is being
- animated, the system cycles through these underlying components,
- displaying each at the appropriate moment. At any given point in
- time the system may be in the process of removing the last
- displayed component and adding in the next one. During such a
- component switch, the system will have two VSprites added for a
- single object: one is in the process of being removed and one is
- in the process of being displayed.
-
- Special Initialization Steps for Complex Gel Collision Detection
-
- When setting-up a multi-component Gel, each underlying VSprite
- structure must be initialized for collision, as the system will
- not look to the others for more information. An AnimOb's
- collision detection information need not be static. The
- collision information can change from frame to frame in the same
- manner image data can change. The example shows a special case,
- where all frames are similar enough that they have identical
- collision information.
-
- The following fields in the VSprite structure must be properly
- initialized for system collision detection: HitMask, MeMask,
- BorderLine and CollMask. HitMask and MeMask tell the system
- which collision routine to call when a collision is detected.
- BorderLine and CollMask are "shadow masks" that are used to
- determine if this component overlaps any other object. These
- values are set just as they would be for a single VSprite or a
- Bob.
-
- Note that it is impossible for components of a single AnimOb's
- sequence to collide with one another. However, in an AnimOb that
- contains multiple sequences, it is possible for a component in
- one sequence to collide with a component from a different
- sequence. This can be prevented through careful selection of
- HitMask and MeMask values, or can be detected in the individual
- collision routines.
-
- What Happens When Complex Gels Collide
-
- Collisions between Animation Objects should be fairly simple to
- process. The DoCollision() routine should examine all displayed
- objects for both overlap of objects and for correct interaction
- between the HitMask and MeMask, then call the appropriate
- collision routine.
-
- Unfortunately, the DoCollision() routine does not ignore the
- previous AnimOb component, which is in the process of being
- removed from the display. These components are moved by the
- system to a position well above and to the left of the visible
- display. When the Gels are next drawn, the removed component
- will be moved off-screen, causing it to disappear from the
- display. At the same time, the new component will be drawn
- on-screen. This would not be a problem if the removed components
- did not overlap, however, all components that are being removed
- are positioned at the same off-screen location. This means that
- they all overlap and collisions will occur between all pairs of
- components that are in the process of being removed.
-
-
- The BOBSAWAY Flag Comes to the Rescue
-
- To handle collisions between pairs of AnimObs, the Gel-to-Gel
- collision routines must ignore the objects that are being
- removed. There are two ways to handle this. The first is to
- check for large negative position values in the X and Y variables
- of the VSprite structure. This works, but is not the best way to
- check for removal. The second, and preferred method, is to look
- at the flags of the associated Bob. If the BOBSAWAY flag is set,
- then the bob is being removed and should not be used in the
- collision routines. Note that this has been changed for 2.0,
- which will only look at active VSprites for collision detection.
-
- The example code is made up of four files:
-
- 1) animtools.h - include file necessary to use
- animtools.
- 2) animtools_proto.h - prototypes for animtools
- functions.
- 3) animtools.c - animtools functions. These
- simplify the use of the animation
- sub-system.
- 4) collide.c - example code.
-
- The example code was published in the latest release of the ROM
- Kernel Manual: Libraries & Devices. It has been updated and
- reprinted here. The example can be compiled and linked using
- Lattice C with these commands:
-
- lc -b1 -cfist -v -y -ocollide.o collide.c
- lc -b1 -cfist -v -y -oanimtools.o animtools.c
- blink from lib:c.o collide.o animtools.o library
- lib:lc.lib lib:amiga.lib to collide.
-
-
-
-
-
- #ifndef GELTOOLS_H
- #define GELTOOLS_H
-
- /* these data structures are used by the functions in animtools.c to
- ** allow for an easier interface to the animation system.
- */
-
- /* data structure to hold information for a new vsprite.
- ** note that:
- ** NEWVSPRITE myNVS;
- ** is equivalent to:
- ** struct newVSprite myNVS;
- */
- typedef struct newVSprite
- {
- WORD *nvs_Image; /* image data for the vsprite */
- WORD *nvs_ColorSet; /* color array for the vsprite */
- SHORT nvs_WordWidth; /* width in words */
- SHORT nvs_LineHeight; /* height in lines */
- SHORT nvs_ImageDepth; /* depth of the image */
- SHORT nvs_X; /* initial x position */
- SHORT nvs_Y; /* initial y position */
- SHORT nvs_Flags; /* vsprite flags */
-
- /* THIS HAS CHANGED for amiga mail. **********************************
- **
- ** Add two lines to the NEWVSPRITE structure.
- ** This allows the created VSprite structures to be initialized with
- ** HitMask and MeMask information.
- */
- USHORT nvs_HitMask; /* Hit mask. */
- USHORT nvs_MeMask; /* Me mask. */
- /*
- ** END OF CHANGE for amiga mail. **********************************
- */
- } NEWVSPRITE;
-
- /* data structure to hold information for a new bob.
- ** note that:
- ** NEWBOB myNBob;
- ** is equivalent to:
- ** struct newBob myNBob;
- */
- typedef struct newBob
- {
- WORD *nb_Image; /* image data for the bob */
- SHORT nb_WordWidth; /* width in words */
- SHORT nb_LineHeight; /* height in lines */
- SHORT nb_ImageDepth; /* depth of the image */
- SHORT nb_PlanePick; /* planes that get image data */
- SHORT nb_PlaneOnOff; /* unused planes to turn on */
- SHORT nb_BFlags; /* bob flags */
- SHORT nb_DBuf; /* 1=double buf, 0=not */
- SHORT nb_RasDepth; /* depth of the raster */
- SHORT nb_X; /* initial x position */
- SHORT nb_Y; /* initial y position */
-
- /* THIS HAS CHANGED for amiga mail. **********************************
- **
- ** Add two lines to the NEWBOB structure.
- ** This is only used to pass the information to the VSprite structure
- ** in the makeBob() routine.
- */
- USHORT nb_HitMask; /* Hit mask. */
- USHORT nb_MeMask; /* Me mask. */
- /*
- ** END OF CHANGE for amiga mail. **********************************
- */
- } NEWBOB ;
-
- /* data structure to hold information for a new animation component.
- ** note that:
- ** NEWANIMCOMP myNAC;
- ** is equivalent to:
- ** struct newAnimComp myNAC;
- */
- typedef struct newAnimComp
- {
- WORD (*nac_Routine)(); /* routine called when Comp is displayed. */
- SHORT nac_Xt; /* initial delta offset position. */
- SHORT nac_Yt; /* initial delta offset position. */
- SHORT nac_Time; /* Initial Timer value. */
- SHORT nac_CFlags; /* Flags for the Component. */
- } NEWANIMCOMP;
-
- /* data structure to hold information for a new animation sequence.
- ** note that:
- ** NEWANIMSEQ myNAS;
- ** is equivalent to:
- ** struct newAnimSeq myNAS;
- */
- typedef struct newAnimSeq
- {
- struct AnimOb *nas_HeadOb; /* common Head of Object. */
- WORD *nas_Images; /* array of Comp image data */
- SHORT *nas_Xt; /* arrays of initial offsets. */
- SHORT *nas_Yt; /* arrays of initial offsets. */
- SHORT *nas_Times; /* array of Initial Timer value. */
- WORD (**nas_Routines)(); /* Array of fns called when comp drawn */
- SHORT nas_CFlags; /* Flags for the Component. */
- SHORT nas_Count; /* Num Comps in seq (= arrays size) */
-
- /* THIS HAS CHANGED for amiga mail. **********************************
- **
- ** Delete two lines from the NEWANIMSEQ structure.
- ** These are removed becaues the information is now contained in the
- ** NEWBOB and NEWVSPRITE structures.
- **
- ** SHORT nas_HitMask;
- ** SHORT nas_MeMask;
- **
- ** END OF CHANGE for amiga mail. **********************************
- */
- SHORT nas_SingleImage; /* one (or count) images. */
- } NEWANIMSEQ;
-
- #endif
-
-
-
- =====================================================================
- =====================================================================
-
- /* animtools_proto.h */
-
- struct GelsInfo *setupGelSys(struct RastPort *rPort, BYTE reserved);
- VOID cleanupGelSys(struct GelsInfo *gInfo, struct RastPort *rPort);
-
- struct VSprite *makeVSprite(NEWVSPRITE *nVSprite);
- struct Bob *makeBob(NEWBOB *nBob);
- struct AnimComp *makeComp(NEWBOB *nBob, NEWANIMCOMP *nAnimComp);
- struct AnimComp *makeSeq(NEWBOB *nBob, NEWANIMSEQ *nAnimSeq);
-
- VOID freeVSprite(struct VSprite *vsprite);
- VOID freeBob(struct Bob *bob, LONG rasdepth);
- VOID freeComp(struct AnimComp *myComp, LONG rasdepth);
- VOID freeSeq(struct AnimComp *headComp, LONG rasdepth);
- VOID freeOb(struct AnimOb *headOb, LONG rasdepth);
-
-
- =====================================================================
- =====================================================================
-
- /* animtools.c 19oct89 original code by Dave Lucas.
- ** rework by (CATS)
- **
- ** This file is a collection of tools which are used with the VSprite, Bob
- ** and Animation system software. It is intended as a useful EXAMPLE, and
- ** while it shows what must be done, it is not the only way to do it.
- ** If Not Enough Memory, or error return, each cleans up after itself
- ** before returning.
- **
- ** NOTE: these routines assume a very specific structure to the
- ** gel lists. make sure that you use the correct pairs together
- ** (i.e. makeOb()/freeOb(), etc.)
- **
- ** lattice c 5.04
- ** lc -b1 -cfist -v -y -oanimtools.o animtools.c
- */
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <graphics/gfx.h>
- #include <graphics/gels.h>
- #include <graphics/clip.h>
- #include <graphics/rastport.h>
- #include <graphics/view.h>
- #include <graphics/gfxbase.h>
-
- /* THIS HAS CHANGED for amiga mail. **********************************
- **
- ** In the RKM it was assumed that animtools stuff was in a different
- ** directory from the example program.
- **
- ** #include "/animtools/animtools.h"
- ** #include "/animtools/animtools_proto.h"
- **
- ** Now they are in the same directory as the example:
- **
- ** END OF CHANGE for amiga mail. **********************************
- */
- #include "animtools.h"
- #include "animtools_proto.h"
-
- #include <proto/all.h>
-
- /*-------------------------------------------------------------
- ** setup the gels system. After this call is made you can use
- ** vsprites, bobs, anim comps, and anim obs.
- **
- ** note that this links the GelsInfo structure into the rast port,
- ** and calls InitGels().
- **
- ** all resources are properly freed on failure.
- **
- ** It uses information in your RastPort structure to establish
- ** boundary collision defaults at the outer edges of the raster.
- **
- ** This routine sets up for everything - collision detection and all.
- **
- ** You must already have run LoadView before ReadyGelSys is called.
- */
- struct GelsInfo *setupGelSys(struct RastPort *rPort, BYTE reserved)
- {
- struct GelsInfo *gInfo;
- struct VSprite *vsHead;
- struct VSprite *vsTail;
-
- if (NULL != (gInfo =
- (struct GelsInfo *)AllocMem((LONG)sizeof(struct GelsInfo), MEMF_CLEAR)))
- {
- if (NULL != (gInfo->nextLine =
- (WORD *)AllocMem((LONG)sizeof(WORD) * 8, MEMF_CLEAR)))
- {
- if (NULL != (gInfo->lastColor =
- (WORD **)AllocMem((LONG)sizeof(LONG) * 8, MEMF_CLEAR)))
- {
- if (NULL != (gInfo->collHandler =
- (struct collTable *)AllocMem((LONG)sizeof(struct collTable),
- MEMF_CLEAR)))
- {
- if (NULL != (vsHead = (struct VSprite *)AllocMem(
- (LONG)sizeof(struct VSprite), MEMF_CLEAR)))
- {
- if (NULL != (vsTail = (struct VSprite *)AllocMem(
- (LONG)sizeof(struct VSprite), MEMF_CLEAR)))
- {
- gInfo->sprRsrvd = reserved;
-
- /* THIS HAS CHANGED for amiga mail. **********************************
- **
- ** In the RKM leftmost and topmost were set to zero.
- **
- ** gInfo->leftmost = 0;
- ** gInfo->topmost = 0;
- **
- ** This has been changed to one to better keep items inside the boundaries
- ** of the display.
- */
- gInfo->leftmost = 1;
- gInfo->topmost = 1;
- /*
- ** END OF CHANGE for amiga mail. **********************************
- */
-
- gInfo->rightmost =
- (rPort->BitMap->BytesPerRow << 3) - 1;
- gInfo->bottommost = rPort->BitMap->Rows - 1;
-
- rPort->GelsInfo = gInfo;
-
- InitGels(vsHead, vsTail, gInfo);
-
- return(gInfo);
- }
- FreeMem(vsHead, (LONG)sizeof(*vsHead));
- }
- FreeMem(gInfo->collHandler, (LONG)sizeof(struct collTable));
- }
- FreeMem(gInfo->lastColor, (LONG)sizeof(LONG) * 8);
- }
- FreeMem(gInfo->nextLine, (LONG)sizeof(WORD) * 8);
- }
- FreeMem(gInfo, (LONG)sizeof(*gInfo));
- }
- return(NULL);
- }
-
- /*-------------------------------------------------------------
- ** free all of the stuff allocated by setupGelSys().
- ** only call this routine if setupGelSys() returned successfully.
- ** the GelsInfo structure is the one returned by setupGelSys().
- **
- ** It also unlinks the GelsInfo from the RastPort.
- */
- VOID cleanupGelSys(struct GelsInfo *gInfo, struct RastPort *rPort)
- {
- rPort->GelsInfo = NULL;
-
- FreeMem(gInfo->collHandler, (LONG)sizeof(struct collTable));
- FreeMem(gInfo->lastColor, (LONG)sizeof(LONG) * 8);
- FreeMem(gInfo->nextLine, (LONG)sizeof(WORD) * 8);
- FreeMem(gInfo->gelHead, (LONG)sizeof(struct VSprite));
- FreeMem(gInfo->gelTail, (LONG)sizeof(struct VSprite));
- FreeMem(gInfo, (LONG)sizeof(*gInfo));
- }
-
- /*-------------------------------------------------------------
- ** create a VSprite from the information given in nVSprite.
- ** use freeVSprite() to free this gel.
- */
- struct VSprite *makeVSprite(NEWVSPRITE *nVSprite)
- {
- struct VSprite *vsprite;
- LONG line_size;
- LONG plane_size;
-
- line_size = (LONG)sizeof(WORD) * nVSprite->nvs_WordWidth;
- plane_size = line_size * nVSprite->nvs_LineHeight;
-
- if (NULL != (vsprite =
- (struct VSprite *)AllocMem((LONG)sizeof(struct VSprite), MEMF_CLEAR)))
- {
- if (NULL != (vsprite->BorderLine =
- (WORD *)AllocMem(line_size, MEMF_CHIP)))
- {
- if (NULL != (vsprite->CollMask =
- (WORD *)AllocMem(plane_size, MEMF_CHIP)))
- {
- vsprite->Y = nVSprite->nvs_Y;
- vsprite->X = nVSprite->nvs_X;
- vsprite->Flags = nVSprite->nvs_Flags;
- vsprite->Width = nVSprite->nvs_WordWidth;
- vsprite->Depth = nVSprite->nvs_ImageDepth;
- vsprite->Height = nVSprite->nvs_LineHeight;
-
- /* THIS HAS CHANGED for amiga mail. **********************************
- **
- ** In the RKM, the vsprite HitMask and MeMask were set to an arbitrary
- ** value (it was assumed that the programmer would later patch these
- ** values if collision detection was required!)
- **
- ** vsprite->MeMask = 1;
- ** vsprite->HitMask = 1;
- **
- ** Here, we have changed the NEWVSPRITE structure to contain these
- ** values, so this routine can set-up both of them.
- */
- vsprite->MeMask = nVSprite->nvs_MeMask;
- vsprite->HitMask = nVSprite->nvs_HitMask;
- /*
- ** END OF CHANGE for amiga mail. **********************************
- */
-
- vsprite->ImageData = nVSprite->nvs_Image;
- vsprite->SprColors = nVSprite->nvs_ColorSet;
- vsprite->PlanePick = 0x00;
- vsprite->PlaneOnOff = 0x00;
-
- InitMasks(vsprite);
- return(vsprite);
- }
- FreeMem(vsprite->BorderLine, line_size);
- }
- FreeMem(vsprite, (LONG)sizeof(*vsprite));
- }
- return(NULL);
- }
-
- /*-------------------------------------------------------------
- ** create a Bob from the information given in nBob.
- ** use freeBob() to free this gel.
- **
- ** A VSprite is created for this bob.
- ** This routine properly allocates all double buffered information
- ** if it is required.
- */
- struct Bob *makeBob(NEWBOB *nBob)
- {
- struct Bob *bob;
- struct VSprite *vsprite;
- NEWVSPRITE nVSprite ;
- LONG rassize;
-
- rassize = (LONG)sizeof(UWORD) *
- nBob->nb_WordWidth * nBob->nb_LineHeight * nBob->nb_RasDepth;
-
- if (NULL != (bob =
- (struct Bob *)AllocMem((LONG)sizeof(struct Bob), MEMF_CLEAR)))
- {
- if (NULL != (bob->SaveBuffer = (WORD *)AllocMem(rassize, MEMF_CHIP)))
- {
- nVSprite.nvs_WordWidth = nBob->nb_WordWidth;
- nVSprite.nvs_LineHeight = nBob->nb_LineHeight;
- nVSprite.nvs_ImageDepth = nBob->nb_ImageDepth;
- nVSprite.nvs_Image = nBob->nb_Image;
- nVSprite.nvs_X = nBob->nb_X;
- nVSprite.nvs_Y = nBob->nb_Y;
- nVSprite.nvs_ColorSet = NULL;
- nVSprite.nvs_Flags = nBob->nb_BFlags;
-
- /* THIS HAS CHANGED for amiga mail. **********************************
- **
- ** The structure of the program has been changed to pass the values
- ** of the HitMask and the MeMask down to the VSprite structure.
- ** Push the values into the NEWVSPRITE structure for use in
- ** makeVSprite().
- */
- nVSprite.nvs_MeMask = nBob->nb_MeMask;
- nVSprite.nvs_HitMask = nBob->nb_HitMask;
- /*
- ** END OF CHANGE for amiga mail. **********************************
- */
-
- if ((vsprite = makeVSprite(&nVSprite)) != NULL)
- {
- vsprite->PlanePick = nBob->nb_PlanePick;
- vsprite->PlaneOnOff = nBob->nb_PlaneOnOff;
-
- vsprite->VSBob = bob;
- bob->BobVSprite = vsprite;
- bob->ImageShadow = vsprite->CollMask;
- bob->Flags = 0;
- bob->Before = NULL;
- bob->After = NULL;
- bob->BobComp = NULL;
-
- if (nBob->nb_DBuf)
- {
- if (NULL != (bob->DBuffer = (struct DBufPacket *)AllocMem(
- (LONG)sizeof(struct DBufPacket), MEMF_CLEAR)))
- {
- if (NULL != (bob->DBuffer->BufBuffer =
- (WORD *)AllocMem(rassize, MEMF_CHIP)))
- {
- return(bob);
- }
- FreeMem(bob->DBuffer, (LONG)sizeof(struct DBufPacket));
- }
- }
- else
- {
- bob->DBuffer = NULL;
- return(bob);
- }
-
- freeVSprite(vsprite);
- }
- FreeMem(bob->SaveBuffer, rassize);
- }
- FreeMem(bob, (LONG)sizeof(*bob));
- }
- return(NULL);
- }
-
- /*-------------------------------------------------------------
- ** create a Animation Component from the information given in nAnimComp
- ** and nBob.
- ** use freeComp() to free this gel.
- **
- ** makeComp calls makeBob(), and links the bob into a AnimComp.
- */
- struct AnimComp *makeComp(NEWBOB *nBob, NEWANIMCOMP *nAnimComp)
- {
- struct Bob *compBob;
- struct AnimComp *aComp;
-
- if ((aComp = AllocMem((LONG)sizeof(struct AnimComp),MEMF_CLEAR)) != NULL)
- {
- if ((compBob = makeBob(nBob)) != NULL)
- {
- compBob->After = NULL; /* Caller can deal with these later. */
- compBob->Before = NULL;
- compBob->BobComp = aComp; /* Link 'em up. */
-
- aComp->AnimBob = compBob;
- aComp->TimeSet = nAnimComp->nac_Time; /* Num ticks active. */
- aComp->YTrans = nAnimComp->nac_Yt; /* Offset rel to HeadOb */
- aComp->XTrans = nAnimComp->nac_Xt;
- aComp->AnimCRoutine = nAnimComp->nac_Routine;
- aComp->Flags = nAnimComp->nac_CFlags;
- aComp->Timer = 0;
- aComp->NextSeq = NULL;
- aComp->PrevSeq = NULL;
- aComp->NextComp = NULL;
- aComp->PrevComp = NULL;
- aComp->HeadOb = NULL;
-
- return(aComp);
- }
- FreeMem(aComp, (LONG)sizeof(struct AnimComp));
- }
- return(NULL);
- }
-
- /*-------------------------------------------------------------
- ** create an Animation Sequence from the information given in nAnimSeq
- ** and nBob.
- ** use freeSeq() to free this gel.
- **
- ** this routine creates a linked list of animation components which
- ** make up the animation sequence.
- **
- ** It links them all up, making a circular list of the PrevSeq
- ** and NextSeq pointers. That is to say, the first component of the
- ** sequences' PrevSeq points to the last component; the last component of
- ** the sequences' NextSeq points back to the first component.
- **
- ** If dbuf is on, the underlying Bobs'll be set up for double buffering.
- ** If singleImage is non-zero, the pImages pointer is assumed to point to
- ** an array of only one image, instead of an array of 'count' images, and
- ** all Bobs will use the same image.
- */
- struct AnimComp *makeSeq(NEWBOB *nBob, NEWANIMSEQ *nAnimSeq)
- {
- int seq;
- struct AnimComp *firstCompInSeq = NULL;
- struct AnimComp *seqComp = NULL;
- struct AnimComp *lastCompMade = NULL;
- LONG image_size;
- NEWANIMCOMP nAnimComp;
-
- /* get the initial image. this is the only image that is used
- ** if nAnimSeq->nas_SingleImage is non-zero.
- */
- nBob->nb_Image = nAnimSeq->nas_Images;
- image_size = nBob->nb_LineHeight * nBob->nb_ImageDepth * nBob->nb_WordWidth;
-
- /* for each comp in the sequence */
- for (seq = 0; seq < nAnimSeq->nas_Count; seq++)
- {
- nAnimComp.nac_Xt = *(nAnimSeq->nas_Xt + seq);
- nAnimComp.nac_Yt = *(nAnimSeq->nas_Yt + seq);
- nAnimComp.nac_Time = *(nAnimSeq->nas_Times + seq);
- nAnimComp.nac_Routine = nAnimSeq->nas_Routines[seq];
- nAnimComp.nac_CFlags = nAnimSeq->nas_CFlags;
-
- if ((seqComp = makeComp(nBob, &nAnimComp)) == NULL)
- {
- if (firstCompInSeq != NULL)
- freeSeq(firstCompInSeq, (LONG)nBob->nb_RasDepth);
- return(NULL);
- }
-
- /* THIS HAS CHANGED for amiga mail. **********************************
- **
- ** Remove these two lines from the RKM. This is because we are now
- ** passing the HitMask and MeMask directly down to the VSprite structure.
- ** NOTE that the deleted technique only sets up the two values for one
- ** VSprite in the AnimComp. The new technique (used in this example)
- ** correctly does the set-up of all the VSprites in the AnimComp.
- **
- ** seqComp->AnimBob->BobVSprite->HitMask = nAnimSeq->nas_HitMask;
- ** seqComp->AnimBob->BobVSprite->MeMask = nAnimSeq->nas_MeMask;
- **
- ** END OF CHANGE for amiga mail. **********************************
- */
- seqComp->HeadOb = nAnimSeq->nas_HeadOb;
-
- /* Make a note of where the first component is. */
- if (firstCompInSeq == NULL)
- firstCompInSeq = seqComp;
-
- /* link the component into the list */
- if (lastCompMade != NULL)
- lastCompMade->NextSeq = seqComp;
-
- seqComp->NextSeq = NULL;
- seqComp->PrevSeq = lastCompMade;
- lastCompMade = seqComp;
-
- /* If nAnimSeq->nas_SingleImage is zero,
- ** the image array has nAnimSeq->nas_Count images.
- */
- if (!nAnimSeq->nas_SingleImage)
- nBob->nb_Image += image_size;
- }
- /* On The last component in the sequence, set Next/Prev to make
- ** the linked list a loop of components.
- */
- lastCompMade->NextSeq = firstCompInSeq;
- firstCompInSeq->PrevSeq = lastCompMade;
-
- return(firstCompInSeq);
- }
-
- /*-------------------------------------------------------------
- ** free the data created by makeVSprite()
- **
- ** assumes images deallocated elsewhere.
- */
- VOID freeVSprite(struct VSprite *vsprite)
- {
- LONG line_size;
- LONG plane_size;
-
- line_size = (LONG)sizeof(WORD) * vsprite->Width;
- plane_size = line_size * vsprite->Height;
-
- FreeMem(vsprite->BorderLine, line_size);
- FreeMem(vsprite->CollMask, plane_size);
-
- FreeMem(vsprite, (LONG)sizeof(*vsprite));
- }
-
- /*-------------------------------------------------------------
- ** free the data created by makeBob()
- **
- ** it's important that rasdepth match the depth you
- ** passed to makeBob() when this gel was made.
- ** assumes images deallocated elsewhere.
- */
- VOID freeBob(struct Bob *bob, LONG rasdepth)
- {
- LONG rassize;
-
- rassize = (LONG)sizeof(UWORD) *
- bob->BobVSprite->Width * bob->BobVSprite->Height * rasdepth;
-
- if (bob->DBuffer != NULL)
- {
- FreeMem(bob->DBuffer->BufBuffer, rassize);
- FreeMem(bob->DBuffer, (LONG)sizeof(struct DBufPacket));
- }
- FreeMem(bob->SaveBuffer, rassize);
- freeVSprite(bob->BobVSprite);
- FreeMem(bob, (LONG)sizeof(*bob));
- }
-
- /*-------------------------------------------------------------
- ** free the data created by makeComp()
- **
- ** it's important that rasdepth match the depth you
- ** passed to makeComp() when this gel was made.
- ** assumes images deallocated elsewhere.
- */
- VOID freeComp(struct AnimComp *myComp, LONG rasdepth)
- {
- freeBob(myComp->AnimBob, rasdepth);
- FreeMem(myComp, (LONG)sizeof(struct AnimComp));
- }
-
- /*-------------------------------------------------------------
- ** free the data created by makeSeq()
- **
- ** Complimentary to makeSeq(), this routine goes through the NextSeq
- ** pointers and frees the Components
- **
- ** This routine only goes forward through the list, and so
- ** it must be passed the first component in the sequence, or the sequence
- ** must be circular (which is guaranteed if you use makeSeq()).
- **
- ** it's important that rasdepth match the depth you
- ** passed to makeSeq() when this gel was made.
- ** assumes images deallocated elsewhere.
- */
- VOID freeSeq(struct AnimComp *headComp, LONG rasdepth)
- {
- struct AnimComp *curComp;
- struct AnimComp *nextComp;
-
- /* this is freeing a loop of AnimComps, hooked together by the
- ** NextSeq and PrevSeq pointers.
- */
-
- /* break the NextSeq loop, so we get a NULL at the end of the list. */
- headComp->PrevSeq->NextSeq = NULL;
-
- curComp = headComp; /* get the start of the list */
- while (curComp != NULL)
- {
- nextComp = curComp->NextSeq;
- freeComp(curComp, rasdepth);
- curComp = nextComp;
- }
- }
-
- /*-------------------------------------------------------------
- ** free an animation object (list of sequences).
- **
- ** freeOb() goes through the NextComp pointers, starting at the AnimObs'
- ** HeadComp, and frees every sequence.
- ** it only goes forward. It then frees the Object itself.
- ** assumes images deallocated elsewhere.
- */
- VOID freeOb(struct AnimOb *headOb, LONG rasdepth)
- {
- struct AnimComp *curSeq;
- struct AnimComp *nextSeq;
-
- curSeq = headOb->HeadComp; /* get the start of the list */
- while (curSeq != NULL)
- {
- nextSeq = curSeq->NextComp;
- freeSeq(curSeq, rasdepth);
- curSeq = nextSeq;
- }
-
- FreeMem(headOb, (LONG)sizeof(struct AnimOb));
- }
-
-
- =====================================================================
- =====================================================================
-
-
- /* collide.c */
- /* This is an example that shows how to do collision detection between
- ** multiple animation objects and between animation objects and the border.
- **
- ** Lattice C 5.04
- ** lc -b1 -cfist -v -y -ocollide.o collide.c
- ** lc -b1 -cfist -v -y -oanimtools.o animtools.c
- ** blink from lib:c.o collide.o animtools.o
- ** library lib:lc.lib lib:amiga.lib to collide
- */
- #include <exec/types.h>
- #include <intuition/intuition.h>
- #include <graphics/gels.h>
- #include <graphics/collide.h>
- #include <exec/memory.h>
- #include <libraries/dos.h>
-
- #include "animtools.h"
- #include "animtools_proto.h"
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <proto/all.h>
- int CXBRK(void) { return(0); }
-
- /* prototypes for functions in this file */
- VOID __stdargs __saveds hit_routine(struct VSprite *vs1,struct VSprite *vs2);
- VOID __stdargs __saveds bounceWall(struct VSprite *vs1,LONG borderflags);
- struct AnimOb *setupBoing(SHORT dbufing);
- VOID runAnimation(struct Window *win, SHORT dbufing,
- struct AnimOb **animKey, struct BitMap **myBitMaps);
- LONG setupPlanes(struct BitMap *bitMap, LONG depth, LONG width, LONG height);
- struct BitMap **setupBitMaps(LONG depth, LONG width, LONG height);
- VOID freePlanes(struct BitMap *bitMap, LONG depth, LONG width, LONG height);
- VOID freeBitMaps(struct BitMap **myBitMaps,
- LONG depth, LONG width, LONG height);
- struct GelsInfo *setupDisplay(struct Window **win, SHORT dbufing,
- struct BitMap **myBitMaps);
- VOID drawGels(struct Window *win, struct AnimOb **animKey,
- SHORT dbufing, WORD *toggleFrame, struct BitMap **myBitMaps);
-
- #define RBMWIDTH 320
- #define RBMHEIGHT 200
- #define RBMDEPTH 4
-
- struct NewScreen ns =
- {
- 0, 0, 320, 200, 2, 0, 1, NULL,
- CUSTOMSCREEN, NULL, "Collision With AnimObs", NULL, NULL
- };
- struct NewWindow nw =
- {
- 50, 50, 220, 100, -1, -1, CLOSEWINDOW,
- WINDOWCLOSE | RMBTRAP, NULL, NULL, "Close Window to Stop", NULL,
- NULL, 150, 100, 150, 100, CUSTOMSCREEN
- };
-
- struct IntuitionBase *IntuitionBase = NULL;
- struct GfxBase *GfxBase = NULL;
-
- int return_code;
-
- /* these give the number of frames (COUNT), size (HEIGHT, WIDTH, DEPTH),
- ** and word width (WWIDTH) of the animated object.
- */
- #define BOING_COUNT 6
- #define BOING_HEIGHT 25
- #define BOING_WIDTH 32
- #define BOING_DEPTH 1
- #define BOING_WWIDTH ((BOING_WIDTH + 15) / 16)
-
- /* these are the IDs for the system to use for the three objects.
- ** these numbers will be used for the collision detection system.
- **
- ** Do not use zero (0), as it is reserved by the collision system
- ** for border hits (see graphics/collide.h, BORDERHIT.)
- */
- #define BOING_1 2
- #define BOING_2 3
- #define BOING_3 4
-
- /* these are the number of counts that each frame is displayed.
- ** they are all one, so each frame is displayed once then the
- ** animation system will move on to the next in the sequence
- */
- SHORT boing3Times[BOING_COUNT] = { 1, 1, 1, 1, 1, 1 };
-
- /* these are all set to zero as we do not want anything added
- ** to the X and Y positions using ring motion control.
- ** all movement is done using the acceleration and velocity
- ** values.
- */
- SHORT boing3YTranses[BOING_COUNT] = { 0, 0, 0, 0, 0, 0 };
- SHORT boing3XTranses[BOING_COUNT] = { 0, 0, 0, 0, 0, 0 };
-
- /* no special routines to call when each anim comp is displayed */
- WORD (*boing3CRoutines[BOING_COUNT])(struct AnimComp *) =
- { NULL, NULL, NULL, NULL, NULL, NULL };
-
- UWORD __chip boing3Image[BOING_COUNT][BOING_WWIDTH * BOING_HEIGHT * BOING_DEPTH]
- =
- {
- /*----- bitmap Boing, frame 0: w = 32, h = 25 ------ */
- {
- 0x0023, 0x0000, 0x004E, 0x3000, 0x00E3, 0x3A00, 0x03C3, 0xC900,
- 0x0787, 0x8780, 0x108F, 0x8700, 0x31F7, 0x8790, 0x61F0, 0x4790,
- 0x63E0, 0xFB90, 0x43E0, 0xF848, 0x3BC0, 0xF870, 0x3801, 0xF870,
- 0x383D, 0xF070, 0x387E, 0x1070, 0x387C, 0x0EE0, 0xD87C, 0x1F10,
- 0x467C, 0x1E10, 0x479C, 0x1E30, 0x6787, 0x3E20, 0x0787, 0xCC60,
- 0x0F0F, 0x8700, 0x048F, 0x0E00, 0x0277, 0x1C00, 0x0161, 0xD800,
- 0x0027, 0x2000,
- },
- /*----- bitmap Boing, frame 1: w = 32, h = 25 ------ */
- {
- 0x0031, 0x8000, 0x0107, 0x1800, 0x00F0, 0x1900, 0x09E1, 0xEC80,
- 0x13C1, 0xE340, 0x1803, 0xE380, 0x387B, 0xC390, 0x30F8, 0x01D0,
- 0x70F8, 0x3DC0, 0xE1F0, 0x3E08, 0x9DF0, 0x7C30, 0x9E30, 0x7C30,
- 0x9E1C, 0x7C30, 0x1C1F, 0x9C30, 0x1C1F, 0x0630, 0x7C1F, 0x0780,
- 0x623F, 0x0798, 0x63DE, 0x0F10, 0x23C1, 0x0F20, 0x33C3, 0xEE20,
- 0x0BC3, 0xC380, 0x0647, 0xC700, 0x023F, 0x8E00, 0x0130, 0xF800,
- 0x0033, 0x8000,
- },
- /*----- bitmap Boing, frame 2: w = 32, h = 25 ------ */
- {
- 0x0019, 0xC000, 0x0103, 0x8800, 0x0278, 0x8D00, 0x0CF0, 0xFE80,
- 0x11F0, 0xF140, 0x0E60, 0xF1E0, 0x1C39, 0xF0C0, 0x1C3E, 0x30C0,
- 0x387E, 0x0CE0, 0xF87C, 0x1F28, 0x8C7C, 0x1F18, 0x8F3C, 0x1F18,
- 0x8F06, 0x1E18, 0x8F07, 0xDE18, 0x8F07, 0xC018, 0x6E0F, 0xC1C0,
- 0x300F, 0x83C8, 0x31EF, 0x8390, 0x31F0, 0x8780, 0x11E0, 0xF720,
- 0x11E1, 0xF1C0, 0x0B61, 0xE300, 0x071B, 0xC600, 0x0138, 0x6C00,
- 0x0031, 0x8000,
- },
- /*----- bitmap Boing, frame 3: w = 32, h = 25 ------ */
- {
- 0x001C, 0xE000, 0x01B1, 0xCC00, 0x031C, 0xC500, 0x0C3C, 0x3680,
- 0x1878, 0x7840, 0x2F70, 0x78E0, 0x0E08, 0x7860, 0x1E0F, 0xB860,
- 0x1C1F, 0x0460, 0xBC1F, 0x07B0, 0xC43F, 0x0788, 0xC7FE, 0x0788,
- 0xC7C0, 0x0F88, 0xC781, 0xEF88, 0xC783, 0xF118, 0x2783, 0xE0E8,
- 0x3983, 0xE1E0, 0x3863, 0xE1C0, 0x1878, 0xC1C0, 0x3878, 0x3380,
- 0x10F0, 0x78C0, 0x0B70, 0xF180, 0x0588, 0xE200, 0x009E, 0x2400,
- 0x0018, 0xC000,
- },
- /*----- bitmap Boing, frame 4: w = 32, h = 25 ------ */
- {
- 0x000E, 0x6000, 0x00F8, 0xE400, 0x030F, 0xE600, 0x061E, 0x1300,
- 0x0C3E, 0x1C80, 0x27FC, 0x1C60, 0x0784, 0x3C60, 0x4F07, 0xFE20,
- 0x8F07, 0xC230, 0x1E0F, 0xC1F0, 0x620F, 0x83C8, 0x61CF, 0x83C8,
- 0x61E1, 0x83C8, 0x63E0, 0x63C8, 0x63E0, 0xF9C8, 0x03E0, 0xF878,
- 0x1DC0, 0xF860, 0x1C21, 0xF0E0, 0x5C3E, 0xF0C0, 0x0C3C, 0x11C0,
- 0x143C, 0x3C40, 0x09B8, 0x3880, 0x05C0, 0x7000, 0x00CF, 0x0400,
- 0x000C, 0x6000,
- },
- /*----- bitmap Boing, frame 5: w = 32, h = 25 ------ */
- {
- 0x0026, 0x2000, 0x00FC, 0x7400, 0x0187, 0x7200, 0x030F, 0x0100,
- 0x0E0F, 0x0E80, 0x319F, 0x0E00, 0x23C6, 0x0F30, 0x63C1, 0xCF30,
- 0x4781, 0xF310, 0x0783, 0xE0D0, 0x7383, 0xE0E0, 0x70C3, 0xE0E0,
- 0x70F9, 0xE1E0, 0x70F8, 0x21E0, 0x70F8, 0x3FE0, 0x91F0, 0x3E38,
- 0x4FF0, 0x7C30, 0x4E10, 0x7C60, 0x4E0F, 0x7860, 0x2E1F, 0x08C0,
- 0x0E1E, 0x0E00, 0x049E, 0x1C80, 0x00E4, 0x3800, 0x00C7, 0x9000,
- 0x000E, 0x6000,
- }
- };
-
- /* these structures contain the initialization data for the animation
- ** sequence.
- */
- NEWBOB newBoingBob =
- {
- NULL, BOING_WWIDTH, BOING_HEIGHT, BOING_DEPTH, 0x2, 0x0,
- SAVEBACK | OVERLAY, 0, RBMDEPTH, 0,0,0,0,
- };
- NEWANIMSEQ newBoingSeq =
- {
- NULL, (WORD *)boing3Image, boing3XTranses, boing3YTranses,
- boing3Times, boing3CRoutines, 0, BOING_COUNT, 0,
- };
-
- /*-------------------------------------------------------------------------
- ** setupBoing()
- **
- ** make a new animation object. since all of the boing balls use the same
- ** underlying data, the initalization structures are hard-coded into the
- ** routine (newBoingBob and newBoingSeq.)
- **
- ** return a pointer to the object if successful, NULL if failure.
- ** set a global error code on failure.
- */
- struct AnimOb *setupBoing(SHORT dbufing)
- {
- struct AnimOb *bngOb;
- struct AnimComp *bngComp;
-
- if (NULL != (bngOb = AllocMem((LONG)sizeof(struct AnimOb), MEMF_CLEAR)))
- {
- newBoingBob.nb_DBuf = dbufing; /* double-buffer status */
- newBoingSeq.nas_HeadOb = bngOb; /* pass down head object */
-
- if (NULL != (bngComp = makeSeq(&newBoingBob, &newBoingSeq)))
- {
- bngOb->HeadComp = bngComp; /* the head comp is the one that */
- /* is returned by makeSeq() */
- return(bngOb);
- }
- FreeMem(bngOb, (LONG)sizeof(struct AnimOb));
- }
- return_code = RETURN_WARN;
- return(NULL);
- }
-
- /*-------------------------------------------------------------------------
- ** runAnimation()
- **
- ** a simple message handling loop that also draws the successive frames.
- */
- VOID runAnimation(struct Window *win, SHORT dbufing,
- struct AnimOb **animKey, struct BitMap **myBitMaps)
- {
- struct IntuiMessage *intuiMsg;
- WORD toggleFrame;
-
- /* toggleFrame is used to keep track of which frame of the double buffered
- ** screen we are currently displaying. the variable must exist for the life
- ** of the displayed objects, so it is defined here.
- */
- toggleFrame = 0;
-
- /* end the loop on a CLOSEWINDOW event */
- for (;;)
- {
- /* draw the gels, then check for messages.
- ** check the messages after each display so we get a quick response.
- */
- drawGels(win, animKey, dbufing, &toggleFrame, myBitMaps);
-
- /* quit on a control_c */
- if (SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
- return;
-
- /* check for a closewindow event, die if found */
- while (intuiMsg = (struct IntuiMessage *)GetMsg(win->UserPort))
- {
- if (intuiMsg->Class == CLOSEWINDOW)
- {
- ReplyMsg((struct Message *)intuiMsg);
- return;
- }
- ReplyMsg((struct Message *)intuiMsg);
- }
- }
- }
-
- /*-------------------------------------------------------------------------
- ** setupPlanes()
- **
- ** called only for double-buffered displays.
- ** allocate and clear each bit-plane in a bitmap structure.
- ** clean-up on failure.
- */
- LONG setupPlanes(struct BitMap *bitMap, LONG depth, LONG width, LONG height)
- {
- SHORT plane_num ;
-
- for (plane_num = 0; plane_num < depth; plane_num++)
- {
- if (NULL != (bitMap->Planes[plane_num] =
- (PLANEPTR)AllocRaster(width, height)))
- BltClear((APTR)(bitMap->Planes[plane_num]), (width / 8) * height, 1);
- else
- {
- freePlanes(bitMap, depth, width, height);
- return_code = RETURN_WARN;
- return(NULL);
- }
- }
- return(TRUE);
- }
-
- /*-------------------------------------------------------------------------
- ** setupBitMaps()
- **
- ** allocate the two bitmaps for a double-buffered display.
- ** routine only called when the display is double-buffered.
- */
- struct BitMap **setupBitMaps(LONG depth, LONG width, LONG height)
- {
- static struct BitMap *myBitMaps[2];
-
- /* allocate the two bit-map structures. these do not have to be in CHIP */
- if (NULL != (myBitMaps[0] =
- (struct BitMap *)AllocMem((LONG)sizeof(struct BitMap), MEMF_CLEAR)))
- {
- if (NULL != (myBitMaps[1] =
- (struct BitMap *)AllocMem((LONG)sizeof(struct BitMap), MEMF_CLEAR)))
- {
- /* initialize the bit maps to the correct size. */
- InitBitMap(myBitMaps[0], (BYTE)depth, (SHORT)width, (SHORT)height);
- InitBitMap(myBitMaps[1], (BYTE)depth, (SHORT)width, (SHORT)height);
-
- /* allocate and initialize the bit-planes for the bit-maps. */
- if (NULL != setupPlanes(myBitMaps[0], depth, width, height))
- {
- if (NULL != setupPlanes(myBitMaps[1], depth, width, height))
- return(myBitMaps);
-
- freePlanes(myBitMaps[0], depth, width, height);
- }
- FreeMem(myBitMaps[1], (LONG)sizeof(struct BitMap));
- }
- FreeMem(myBitMaps[0], (LONG)sizeof(struct BitMap));
- }
- /* on failure, everything is freed and a global return code is set. */
- return_code = RETURN_WARN;
- return(NULL);
- }
-
- /*-------------------------------------------------------------------------
- ** freePlanes()
- **
- ** free all of the bit-planes in a bit-map structure.
- */
- VOID freePlanes(struct BitMap *bitMap, LONG depth, LONG width, LONG height)
- {
- SHORT plane_num ;
-
- for (plane_num = 0; plane_num < depth; plane_num++)
- {
- if (NULL != bitMap->Planes[plane_num])
- FreeRaster(bitMap->Planes[plane_num], (USHORT)width, (USHORT)height);
- }
- }
-
- /*-------------------------------------------------------------------------
- ** freeBitMaps()
- **
- ** free the two bit-maps from the double buffered display.
- ** the bit-planes are freed first, then the bit-map structures.
- */
- VOID freeBitMaps(struct BitMap **myBitMaps, LONG depth, LONG width, LONG height)
- {
- freePlanes(myBitMaps[0], depth, width, height);
- freePlanes(myBitMaps[1], depth, width, height);
-
- FreeMem(myBitMaps[0], (LONG)sizeof(struct BitMap));
- FreeMem(myBitMaps[1], (LONG)sizeof(struct BitMap));
- }
-
- /*-------------------------------------------------------------------------
- ** setupDisplay()
- **
- ** open the screen and the window for the display.
- **
- ** if using double buffered display, assume the bit-maps have been opened
- ** and correctly set-up.
- */
- struct GelsInfo *setupDisplay(struct Window **win, SHORT dbufing,
- struct BitMap **myBitMaps)
- {
- struct GelsInfo *gInfo;
- struct Screen *screen;
-
- /* if double-buffered, set-up the new screen structure for custom bit map */
- if (dbufing)
- {
- ns.Type |= CUSTOMBITMAP;
- ns.CustomBitMap = myBitMaps[0];
- }
-
- /* open everything. check for failure. */
- if ((screen = (struct Screen *)OpenScreen(&ns)) != NULL)
- {
- nw.Screen = screen;
- if ((*win = (struct Window *)OpenWindow(&nw)) != NULL)
- {
- if (dbufing)
- {
- /* we are double buffered. set the rastport for it. */
- (*win)->WScreen->RastPort.Flags = DBUFFER;
-
- /* this copies the intuition display (close gadget) to the
- ** second bit-map so the display does not flash when we change
- ** between them.
- */
- (*win)->WScreen->RastPort.BitMap = myBitMaps[1];
- BltBitMapRastPort(myBitMaps[0], 0,0, &(*win)->WScreen->RastPort,
- 0,0, RBMWIDTH, RBMHEIGHT, 0xC0);
- (*win)->WScreen->RastPort.BitMap = myBitMaps[0];
- }
-
- /* ready the gel system for accepting objects
- ** this is only done once for each rastport in use.
- */
- if (NULL != (gInfo = setupGelSys(&(*win)->WScreen->RastPort, 0xFC)))
- return(gInfo);
-
- CloseWindow(*win);
- }
- CloseScreen(screen);
- }
- /* on an error everything is cleaned-up, and a global return code is set. */
- return_code = RETURN_WARN;
- return(NULL);
- }
-
- /*-------------------------------------------------------------------------
- ** drawGels()
- **
- ** handle the update of the display. Animate the simulation and check for
- ** collisions. If the screen is double buffered, swap the bit map as
- ** required.
- */
- VOID drawGels(struct Window *win, struct AnimOb **animKey, SHORT dbufing,
- WORD *toggleFrame, struct BitMap **myBitMaps)
- {
- /* do the required animation stuff. you must sort both after the animate
- ** call and after the collision call.
- */
- Animate((struct AnimOb *)animKey, &win->WScreen->RastPort);
- SortGList(&win->WScreen->RastPort);
-
- DoCollision(&win->WScreen->RastPort);
- SortGList(&win->WScreen->RastPort);
-
- /* toggle if double buffered */
- if (dbufing)
- win->WScreen->ViewPort.RasInfo->BitMap = myBitMaps[*toggleFrame];
-
- /* draw the new position of the gels into the screen. */
- DrawGList(&win->WScreen->RastPort, &win->WScreen->ViewPort);
-
- /* if using a double buffered display, you have a more complicated
- ** update procedure.
- **
- ** if not, then simply use WaitTOF().
- */
- if (dbufing)
- {
- MakeScreen(win->WScreen);
- RethinkDisplay();
-
- *toggleFrame ^= 1;
- win->WScreen->RastPort.BitMap = myBitMaps[*toggleFrame];
- }
- else
- WaitTOF();
- }
-
- /*-------------------------------------------------------------------------
- ** bounceWall()
- **
- ** handle bouncing the animation objects off of the walls.
- **
- ** use __stdargs and __saveds because this routine is not directly called
- ** by this program. The call to DoCollision() causes a call back to
- ** this routine when an animation object comes in contact with a wall.
- ** __stdargs says the arguments are passed on the stack.
- ** __saveds says to restore the data segment pointer on entry to the routine.
- */
- VOID __stdargs __saveds bounceWall(struct VSprite *vs1,LONG borderflags)
- {
- struct AnimOb *ob;
-
- /* get a pointer to the object from the sprite pointer. */
- ob = vs1->VSBob->BobComp->HeadOb;
-
- /* check for hits and act apropriately.
- ** for right and left, reverse the x velocity if the object is moving
- ** towards the wall (it may have already reversed but still be in contact
- ** with the wall.)
- ** for the bottom and top you also have to subtract out the velocity.
- */
- if (((borderflags & RIGHTHIT) && (ob->XVel > 0)) ||
- ((borderflags & LEFTHIT) && (ob->XVel < 0)))
- ob->XVel = -(ob->XVel);
- else if (((borderflags & TOPHIT) && (ob->YVel < 0)) ||
- ((borderflags & BOTTOMHIT) && (ob->YVel > 0)))
- {
- ob->YVel -= ob->YAccel;
- ob->YVel = -(ob->YVel);
- }
- }
-
- /*-------------------------------------------------------------------------
- ** hit_routine()
- **
- ** handle the collision between two animation objects.
- ** this routine simulates objects bouncing off of each other.
- ** this does not do a very good job of it, it does not take into account
- ** the angle of the collision or real physics.
- ** if anyone wants to fix it, please feel free.
- **
- ** use __stdargs and __saveds because this routine is not directly called
- ** by this program. The call to DoCollision() causes a call back to
- ** this routine when two animation objects overlap.
- ** __stdargs says the arguments are passed on the stack.
- ** __saveds says to restore the data segment pointer on entry to the routine.
- */
- VOID __stdargs __saveds hit_routine(struct VSprite *vs1,struct VSprite *vs2)
- {
- LONG vel1, vel2;
-
- /* check that the bob is not being removed! This is due to a 1.3 bug
- ** where all bobs are tested for collision, even the ones that are in
- ** the process of being removed. See text for more information.
- **
- ** bobs are moved to a very large negative position as they are being
- ** removed. if the BOBSAWAY flag is set, then both bobs in the collision
- ** are in the process of being removed--don't do anything in the collision
- ** routine.
- */
- if (!(vs1->VSBob->Flags & BOBSAWAY))
- {
- /* cache the velocity values
- ** Do the X values first (order is not important.)
- */
- vel1 = vs1->VSBob->BobComp->HeadOb->XVel;
- vel2 = vs2->VSBob->BobComp->HeadOb->XVel;
-
- /* if the two objects are moving in the opposite direction (X component)
- ** then negate the velocities.
- ** else swap the velocities.
- */
- if (((vel1 > 0) && (vel2 < 0)) || ((vel1 < 0) && (vel2 > 0)))
- {
- vs1->VSBob->BobComp->HeadOb->XVel = -vel1;
- vs2->VSBob->BobComp->HeadOb->XVel = -vel2;
- }
- else
- {
- vs1->VSBob->BobComp->HeadOb->XVel = vel2;
- vs2->VSBob->BobComp->HeadOb->XVel = vel1;
- }
-
- /* cache the velocity values
- ** Do the Y values second (order is not important.)
- */
- vel1 = vs1->VSBob->BobComp->HeadOb->YVel;
- vel2 = vs2->VSBob->BobComp->HeadOb->YVel;
-
- /* if the two objects are moving in the opposite direction (Y component)
- ** then negate the velocities.
- ** else swap the velocities.
- */
- if (((vel1 > 0) && (vel2 < 0)) || ((vel1 < 0) && (vel2 > 0)))
- {
- vs1->VSBob->BobComp->HeadOb->YVel = -vel1;
- vs2->VSBob->BobComp->HeadOb->YVel = -vel2;
- }
- else
- {
- vs1->VSBob->BobComp->HeadOb->YVel = vel2;
- vs2->VSBob->BobComp->HeadOb->YVel = vel1;
- }
- }
- }
-
- /*-------------------------------------------------------------------------
- ** main routine
- **
- ** run a double buffered display if the user puts any arguments on the
- ** command line.
- **
- ** open libraries, set-up the display, set-up the animation system and
- ** the objects, set-up collisions between objects and against walls,
- ** and run the thing.
- **
- ** clean-up and close resources when done.
- */
- VOID main(int argc, char **argv)
- {
- struct BitMap **myBitMaps;
- struct AnimOb *boingOb;
- struct AnimOb *boing2Ob;
- struct AnimOb *boing3Ob;
- struct Window *win;
- struct Screen *screen;
- struct GelsInfo *gInfo;
- struct AnimOb *animKey;
- SHORT dbufing;
-
- return_code = RETURN_OK;
-
- /* if any arguments, use double-buffering */
- if (argc > 1)
- dbufing = 1;
- else
- dbufing = 0;
-
- /* open required libraries */
- if (NULL == (IntuitionBase = (struct IntuitionBase *)
- OpenLibrary("intuition.library", 33L)))
- return_code = RETURN_FAIL;
- else
- {
- if (NULL == (GfxBase = (struct GfxBase *)
- OpenLibrary("graphics.library", 33L)))
- return_code = RETURN_FAIL;
- else
- {
- /* note that setupBitMaps() will only be called if
- ** we are double buffering
- */
- if ((!dbufing) ||
- (NULL != (myBitMaps=setupBitMaps(RBMDEPTH,RBMWIDTH,RBMHEIGHT))))
- {
- if (NULL != (gInfo = setupDisplay(&win,dbufing,myBitMaps)))
- {
- /* you have to initialize the animation key
- ** before you use it.
- */
- InitAnimate(&animKey);
-
- /* set-up the first boing ball.
- ** all of these use the same data, hard coded into setupBoing().
- ** change the color by changing PlanePick.
- ** set the ID of the ball (MeMask) to BOING_1.
- ** HitMask = 0xFF means that it will collide with everything.
- */
- newBoingBob.nb_PlanePick = 0x2;
- newBoingBob.nb_MeMask = 1L<<BOING_1;
- newBoingBob.nb_HitMask = 0xFF;
- if (NULL != (boingOb = setupBoing(dbufing)))
- {
- /* pick an initial position, velocity and acceleration
- ** and add the object to the system. NOTE that the
- ** Y-velocity and X-acceleration are not set (they default
- ** to zero.) This means that the objects will maintain
- ** a constant movement to the left or right, and will
- ** rely on the Y accelleration for the downward movement.
- ** The collision routines change these values, producing
- ** bouncing off of walls and other objects.
- **
- ** NOTE: ANFRACSIZE is a value that shifts animation
- ** constants past an internal decimal point. If you
- ** do not do this, then the values will only be some
- ** fraction of what you expect. See the Rom Kernel
- ** Manual: Libraries and Devices.
- */
- boingOb->AnY = 10 << ANFRACSIZE;
- boingOb->AnX = 250 << ANFRACSIZE;
- boingOb->XVel = -(4 << ANFRACSIZE);
- boingOb->YAccel = 70;
- AddAnimOb(boingOb, (APTR)&animKey,
- &win->WScreen->RastPort);
-
- /* do the second object--see above comments. */
- newBoingBob.nb_PlanePick = 0x1;
- newBoingBob.nb_MeMask = 1L<<BOING_2;
- newBoingBob.nb_HitMask = 0xFF;
- if (NULL != (boing2Ob = setupBoing(dbufing)))
- {
- boing2Ob->AnY = 50 << ANFRACSIZE;
- boing2Ob->AnX = 50 << ANFRACSIZE;
- boing2Ob->XVel = 3 << ANFRACSIZE;
- boing2Ob->YAccel = 70;
- AddAnimOb(boing2Ob, (APTR)&animKey,
- &win->WScreen->RastPort);
-
- /* do the second object--see above comments.
- ** here we also use PlaneOnOff to change the color.
- */
- newBoingBob.nb_PlanePick = 0x1;
- newBoingBob.nb_PlaneOnOff= 0x2;
- newBoingBob.nb_MeMask = 1L<<BOING_3;
- newBoingBob.nb_HitMask = 0xFF;
- if (NULL != (boing3Ob = setupBoing(dbufing)))
- {
- boing3Ob->AnY = 80 << ANFRACSIZE;
- boing3Ob->AnX = 150<< ANFRACSIZE;
- boing3Ob->XVel = 2 << ANFRACSIZE;
- boing3Ob->YAccel = 70;
- AddAnimOb(boing3Ob, (APTR)&animKey,
- &win->WScreen->RastPort);
-
- /* set up the collisions between boing balls.
- ** NOTE that they all call the same routine.
- */
- SetCollision(BOING_1,hit_routine,gInfo);
- SetCollision(BOING_2,hit_routine,gInfo);
- SetCollision(BOING_3,hit_routine,gInfo);
-
- /* set the collisions with the walls. */
- SetCollision(BORDERHIT,bounceWall,gInfo);
-
- /* everything set-up...run the animation. */
- runAnimation(win, dbufing, &animKey, myBitMaps);
-
- /* done...
- ** free-up everything and clean up the mess.
- */
- freeOb(boing3Ob, RBMDEPTH);
- }
- freeOb(boing2Ob, RBMDEPTH);
- }
- freeOb(boingOb, RBMDEPTH);
- }
-
- cleanupGelSys(gInfo, &win->WScreen->RastPort);
- screen = win->WScreen;
- CloseWindow(win);
- CloseScreen(screen);
- }
-
- if (dbufing)
- freeBitMaps(myBitMaps, RBMDEPTH, RBMWIDTH, RBMHEIGHT);
- }
- CloseLibrary((struct Library *)GfxBase);
- }
- CloseLibrary((struct Library *)IntuitionBase);
- }
-
- /* return the global return code to the system. */
- exit(return_code);
- }
-